﻿
<title>WebRTC Desktop Viewer | Muaz Khan</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">

<meta name="description" content="This WebRTC Experiment page shows privately shared screens, desktops, and parts of the screens." />
<meta name="keywords" content="WebRTC,Desktop-Sharing,Screen-Sharing,RTCWeb,WebRTC-Experiment,WebRTC-Demo" />

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel="author" type="text/html" href="https://plus.google.com/+MuazKhan">
<meta name="author" content="Muaz Khan">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

<script src="https://cdn.webrtc-experiment.com/RTCMultiConnection.js"> </script>
<script src="https://cdn.webrtc-experiment.com/RTCMultiConnection/CodecsHandler.js"></script>
<script src="https://cdn.webrtc-experiment.com/RTCMultiConnection/IceServersHandler.js"></script>
<script src="https://cdn.webrtc-experiment.com/view/websocket.js"> </script>

<style>
body,
html {
    background: black;
    text-align: center;
    color: white;
    overflow: hidden;
}
.local-media,
.remote-media {
    max-width: 100%;
    max-height: 70%;
}
.local-media-small,
.remote-media-small {
    width: 20%;
    position: fixed;
    bottom: 0;
    left: 0;
}
button {
    display: inline-block;
    outline: 0;
    color: white;
    background: #4472b9;
    white-space: nowrap;
    border: 5px solid #4472b9 !important;
    font-family: 'Gotham Rounded A', 'Gotham Rounded B', sans-serif;
    font-weight: 500;
    font-style: normal;
    padding: 9px 16px !important;
    line-height: 1.4;
    position: relative;
    border-radius: 10px;
    -webkit-box-shadow: 5px 5px 0 0 rgba(0, 0, 0, 0.15);
    box-shadow: 5px 5px 0 0 rgba(0, 0, 0, 0.15);
    -webkit-transition: 0.1s;
    transition: 0.1s;
}
button:hover,
button:active,
button:focus {
    background: #04C;
}
button[disabled] {
    background: transparent;
    border-color: rgb(83, 81, 81);
    color: rgb(139, 133, 133);
}
#container {
    -webkit-perspective: 1000;
    background-color: #000000;
    height: 100%;
    margin: 0px auto;
    position: absolute;
    width: 100%;
}
#card {
    -webkit-transform-style: preserve-3d;
    -webkit-transition-duration: 2s;
    -webkit-transition-property: rotation;
}
#local {
    -webkit-backface-visibility: hidden;
    -webkit-transform: scale(-1, 1);
    position: absolute;
    width: 100%;
}
#remote {
    -webkit-backface-visibility: hidden;
    -webkit-transform: rotateY(180deg);
    position: absolute;
    width: 100%;
}
#mini {
    /* -webkit-transform: scale(-1, 1); */

    bottom: 0;
    height: 30%;
    opacity: 1.0;
    position: absolute;
    right: 4px;
    width: 30%;
}
#remoteVideo {
    -webkit-transition-duration: 2s;
    -webkit-transition-property: opacity;
    height: 100%;
    opacity: 0;
    width: 100%;
}
#info-bar {
    background-color: #15DBFF;
    bottom: 55%;
    color: rgb(255, 255, 255);
    font-size: 25px;
    font-weight: bold;
    height: 38px;
    line-height: 38px;
    position: absolute;
    text-align: center;
    width: 100%;
    text-shadow: 1px 1px rgb(14, 105, 137);
    border: 2px solid rgb(47, 102, 118);
    box-shadow: 0 0 6px white;
}
</style>

<div id="container" ondblclick="enterFullScreen()">
    <div id="card">
        <div id="remote">
            <video id="remoteVideo" autoplay="autoplay"></video>
        </div>
    </div>

    <div id="info-bar"></div>
</div>

<script>
(function() {
    var params = {},
        r = /([^&=]+)=?([^&]*)/g;

    function d(s) {
        return decodeURIComponent(s.replace(/\+/g, ' '));
    }

    var match, search = window.location.search;
    while (match = r.exec(search.substring(1)))
        params[d(match[1])] = d(match[2]);

    window.params = params;
})();

function setBandwidth(connection) {
    // www.RTCMultiConnection.org/docs/bandwidth/
    connection.bandwidth = {};
    connection.bandwidth.video = connection.bandwidth.screen = 512;
    connection.bandwidth.audio = 128;

    connection.processSdp = function(sdp) {
        if (DetectRTC.isMobileDevice || DetectRTC.browser.name === 'Firefox') {
            return sdp;
        }

        sdp = CodecsHandler.setApplicationSpecificBandwidth(sdp, connection.bandwidth, !!connection.session.screen);
        sdp = CodecsHandler.setVideoBitrates(sdp, {
            min: connection.bandwidth.video * 8 * 1024,
            max: connection.bandwidth.video * 8 * 1024
        });
        sdp = CodecsHandler.setOpusAttributes(sdp, {
            maxaveragebitrate: connection.bandwidth.audio * 8 * 1024,
            maxplaybackrate: connection.bandwidth.audio * 8 * 1024,
            stereo: 1,
            maxptime: 3
        });
        sdp = CodecsHandler.preferVP9(sdp);
        return sdp;
    };
}

// http://www.rtcmulticonnection.org/docs/constructor/
var connection = new RTCMultiConnection(params.s);

connection.getExternalIceServers = false;
connection.iceServers = IceServersHandler.getIceServers();

setBandwidth(connection);

connection.optionalArgument = {
    optional: [{
        DtlsSrtpKeyAgreement: true
    }, {
        googImprovedWifiBwe: true
    }, {
        googScreencastMinBitrate: 300 * 8 * 1024
    }, {
        googIPv6: true
    }, {
        googDscp: true
    }, {
        googCpuUnderuseThreshold: 55
    }, {
        googCpuOveruseThreshold: 85
    }, {
        googSuspendBelowMinBitrate: true
    }, {
        googCpuOveruseDetection: true
    }],
    mandatory: {}
};
</script>

<script>
// DOM objects
var remoteVideo = document.getElementById('remoteVideo');
var card = document.getElementById('card');
var containerDiv;

if (navigator.mozGetUserMedia) {
    attachMediaStream = function(element, stream) {
        console.log("Attaching media stream");
        element.mozSrcObject = stream;
        element.play();
    };
    reattachMediaStream = function(to, from) {
        console.log("Reattaching media stream");
        to.mozSrcObject = from.mozSrcObject;
        to.play();
    };
} else if (navigator.webkitGetUserMedia) {
    attachMediaStream = function(element, stream) {
        if (typeof element.srcObject !== 'undefined') {
            element.srcObject = stream;
        } else if (typeof element.mozSrcObject !== 'undefined') {
            element.mozSrcObject = stream;
        } else if (typeof element.src !== 'undefined') {
            element.src = URL.createObjectURL(stream);
        } else {
            console.log('Error attaching stream to element.');
        }
    };
    reattachMediaStream = function(to, from) {
        to.src = from.src;
    };
} else {
    console.log("Browser does not appear to be WebRTC-capable");
}
// onstream event; fired both for local and remote videos

var infoBar = document.getElementById('info-bar');

connection.onstatechange = function(state) {
    infoBar.innerHTML = state.name + ': ' + state.reason;

    if(state.name == 'request-rejected' && params.p) {
        infoBar.innerHTML = 'Password (' + params.p + ') did not match with broadcaster, that is why your participation request has been rejected.<br>Please contact him and ask for valid password.';
    }

    if(state.name === 'room-not-available') {
        infoBar.innerHTML = 'Screen share session is closed or paused. You will join automatically when share session is resumed.';
    }
};

connection.onstreamid = function(event) {
    infoBar.innerHTML = 'Remote peer is about to send his screen.';
};

connection.onstream = function(e) {
    if (e.type == 'remote') {
        infoBar.style.display = 'none';
        remoteStream = e.stream;
        attachMediaStream(remoteVideo, e.stream);
        waitForRemoteVideo();
        remoteVideo.setAttribute('data-id', e.userid);

        websocket.send('received-your-screen');
    }
};
// if user left
connection.onleave = function(e) {
    transitionToWaiting();
    connection.onSessionClosed();
};

connection.onSessionClosed = function() {
    infoBar.innerHTML = 'Screen sharing has been closed.';
    infoBar.style.display = 'block';
    connection.close();
    websocket.onopen();

    remoteVideo.pause();
    remoteVideo.src = 'https://cdn.webrtc-experiment.com/images/muted.png';
};

connection.ondisconnected = connection.onSessionClosed;
connection.onstreamended = connection.onSessionClosed;

function waitForRemoteVideo() {
    // Call the getVideoTracks method via adapter.js.
    var videoTracks = remoteStream.getVideoTracks();
    if (videoTracks.length === 0 || remoteVideo.currentTime > 0) {
        transitionToActive();
    } else {
        setTimeout(waitForRemoteVideo, 100);
    }
}

function transitionToActive() {
    remoteVideo.style.opacity = 1;
    card.style.webkitTransform = 'rotateY(180deg)';
    window.onresize();
}

function transitionToWaiting() {
        card.style.webkitTransform = 'rotateY(0deg)';
        remoteVideo.style.opacity = 0;
    }
    // Set the video displaying in the center of window.
window.onresize = function() {
    var aspectRatio;
    if (remoteVideo.style.opacity === '1') {
        aspectRatio = remoteVideo.videoWidth / remoteVideo.videoHeight;
    } else {
        return;
    }
    var innerHeight = this.innerHeight;
    var innerWidth = this.innerWidth;
    var videoWidth = innerWidth < aspectRatio * window.innerHeight ?
        innerWidth : aspectRatio * window.innerHeight;
    var videoHeight = innerHeight < window.innerWidth / aspectRatio ?
        innerHeight : window.innerWidth / aspectRatio;
    containerDiv = document.getElementById('container');
    containerDiv.style.width = videoWidth + 'px';
    containerDiv.style.height = videoHeight + 'px';
    containerDiv.style.left = (innerWidth - videoWidth) / 2 + 'px';
    containerDiv.style.top = (innerHeight - videoHeight) / 2 + 'px';
};

function enterFullScreen() {
    container.webkitRequestFullScreen();
}
</script>

<script>
// using websockets as signaling medium
// http://www.rtcmulticonnection.org/docs/openSignalingChannel/
// using websockets for signaling
// www.RTCMultiConnection.org/docs/openSignalingChannel/
var onMessageCallbacks = {};
var pub = 'pub-c-3c0fc243-9892-4858-aa38-1445e58b4ecb';
var sub = 'sub-c-d0c386c6-7263-11e2-8b02-12313f022c90';

WebSocket = PUBNUB.ws;
var websocket = new WebSocket('wss://pubsub.pubnub.com/' + pub + '/' + sub + '/' + connection.channel);

websocket.onmessage = function(e) {
    data = JSON.parse(e.data);

    if (data.sender == connection.userid) return;

    if (onMessageCallbacks[data.channel]) {
        onMessageCallbacks[data.channel](data.message);
    };
};

websocket.push = websocket.send;
websocket.send = function(data) {
    data.sender = connection.userid;
    websocket.push(JSON.stringify(data));
};

// overriding "openSignalingChannel" method
connection.openSignalingChannel = function(config) {
    var channel = config.channel || this.channel;
    onMessageCallbacks[channel] = config.onmessage;

    if (config.onopen) setTimeout(config.onopen, 1000);

    // directly returning socket object using "return" statement
    return {
        send: function(message) {
            websocket.send({
                sender: connection.userid,
                channel: channel,
                message: message
            });
        },
        channel: channel
    };
};

websocket.onerror = function() {
    if(connection.numberOfConnectedUsers <= 0) {
        location.reload();
    }
};

websocket.onclose = function() {
    if(connection.numberOfConnectedUsers <= 0) {
        location.reload();
    }
};

infoBar.innerHTML = 'Connecting WebSockets server.';

websocket.onopen = function() {
    infoBar.innerHTML = 'WebSockets connection is opened.';

    var sessionDescription = {
        userid: params.s,
        extra: {},
        session: {
            video: true,
            oneway: true
        },
        sessionid: params.s
    };

    if (params.s) {
        infoBar.innerHTML = 'Joining session: ' + params.s;

        if(params.p) {
            // it seems a password protected room.
            connection.extra.password = params.p;
        }

        // http://www.rtcmulticonnection.org/docs/join/
        connection.join(sessionDescription);
    }
};

window.addEventListener('offline', function() {
    infoBar.innerHTML = 'You seems offLine.';
}, false);

window.addEventListener('online', function() {
    infoBar.innerHTML = 'You seems onLine. Reloading the page..';
    location.reload();
}, false);
</script>
